package contacts

// 成员接口
import (
	"encoding/json"
	"errors"
	"fmt"

	"gitee.com/littletow/qywx/services/commons"
)

const (
	// 创建成员URL
	CreateUserURL              string = "https://qyapi.weixin.qq.com/cgi-bin/user/create"
	UpdateUserURL              string = "https://qyapi.weixin.qq.com/cgi-bin/user/update"
	DeleteUserURL              string = "https://qyapi.weixin.qq.com/cgi-bin/user/delete"
	GetUserURL                 string = "https://qyapi.weixin.qq.com/cgi-bin/user/get"
	BatchDeleteUserURL         string = "https://qyapi.weixin.qq.com/cgi-bin/user/batchdelete"
	GetDepartmentUserURL       string = "https://qyapi.weixin.qq.com/cgi-bin/user/simplelist"
	GetDepartmentUserDetailURL string = "https://qyapi.weixin.qq.com/cgi-bin/user/list"
	InviteUserURL              string = "https://qyapi.weixin.qq.com/cgi-bin/batch/invite"
	GetJoinQrcodeURL           string = "https://qyapi.weixin.qq.com/cgi-bin/corp/get_join_qrcode"
	GetActiveStatURL           string = "https://qyapi.weixin.qq.com/cgi-bin/user/get_active_stat"
)

// CreateUserReq 创建成员请求，目前没有添加扩展属性
type CreateUserReq struct {
	UserID           string `json:"userid"`                      // 成员UserID
	Name             string `json:"name"`                        // 成员名称
	Alias            string `json:"alias,omitempty"`             // 成员别名
	Mobile           string `json:"mobile"`                      // 手机号码。企业内必须唯一，mobile/email二者不能同时为空
	Department       []int  `json:"department"`                  // 成员所属部门id列表,不超过100个
	Order            []int  `json:"order,omitempty"`             // 部门内的排序值，默认为0，成员次序以创建时间从小到大排列。个数必须和参数department的个数一致，数值越大排序越前面。有效的值范围是[0, 2^32)
	Position         string `json:"position,omitempty"`          // 职务信息。长度为0~128个字符
	Gender           int    `json:"gender,omitempty"`            // 性别。1表示男性，2表示女性
	Email            string `json:"email"`                       // 邮箱。长度6~64个字节，且为有效的email格式。企业内必须唯一，mobile/email二者不能同时为空
	Telephone        string `json:"telephone,omitempty"`         // 座机。32字节以内，由纯数字或’-‘号组成。
	IsLeaderInDept   []int  `json:"is_leader_in_dept,omitempty"` // 个数必须和参数department的个数一致，表示在所在的部门内是否为上级。1表示为上级，0表示非上级。在审批等应用里可以用来标识上级审批人
	AvatarMediaID    string `json:"avatar_mediaid,omitempty"`    // 成员头像的mediaid，通过素材管理接口上传图片获得的mediaid
	Enable           int    `json:"enable,omitempty"`            // 启用/禁用成员。1表示启用成员，0表示禁用成员
	ExternalPosition string `json:"external_position,omitempty"` // 对外职务，如果设置了该值，则以此作为对外展示的职务，否则以position来展示。长度12个汉字内
	Address          string `json:"address,omitempty"`           // 地址。长度最大128个字符
	MainDepartment   int    `json:"main_department,omitempty"`   // 主部门
	ToInvite         bool   `json:"to_invite,omitempty"`         // 是否邀请该成员使用企业微信（将通过微信服务通知或短信或邮件下发邀请，每天自动下发一次，最多持续3个工作日），默认值为true。
}

// UpdateUserReq 创建成员请求，目前没有添加扩展属性
type UpdateUserReq struct {
	UserID           string `json:"userid"`                      // 成员UserID
	Name             string `json:"name,omitempty"`              // 成员名称
	Alias            string `json:"alias,omitempty"`             // 成员别名
	Mobile           string `json:"mobile,omitempty"`            // 手机号码。企业内必须唯一，mobile/email二者不能同时为空
	Department       []int  `json:"department,omitempty"`        // 成员所属部门id列表,不超过100个
	Order            []int  `json:"order,omitempty"`             // 部门内的排序值，默认为0，成员次序以创建时间从小到大排列。个数必须和参数department的个数一致，数值越大排序越前面。有效的值范围是[0, 2^32)
	Position         string `json:"position,omitempty"`          // 职务信息。长度为0~128个字符
	Gender           int    `json:"gender,omitempty"`            // 性别。1表示男性，2表示女性
	Email            string `json:"email,omitempty"`             // 邮箱。长度6~64个字节，且为有效的email格式。企业内必须唯一，mobile/email二者不能同时为空
	Telephone        string `json:"telephone,omitempty"`         // 座机。32字节以内，由纯数字或’-‘号组成。
	IsLeaderInDept   []int  `json:"is_leader_in_dept,omitempty"` // 个数必须和参数department的个数一致，表示在所在的部门内是否为上级。1表示为上级，0表示非上级。在审批等应用里可以用来标识上级审批人
	AvatarMediaID    string `json:"avatar_mediaid,omitempty"`    // 成员头像的mediaid，通过素材管理接口上传图片获得的mediaid
	Enable           int    `json:"enable,omitempty"`            // 启用/禁用成员。1表示启用成员，0表示禁用成员
	ExternalPosition string `json:"external_position,omitempty"` // 对外职务，如果设置了该值，则以此作为对外展示的职务，否则以position来展示。长度12个汉字内
	Address          string `json:"address,omitempty"`           // 地址。长度最大128个字符
	MainDepartment   int    `json:"main_department,omitempty"`   // 主部门
	ToInvite         bool   `json:"to_invite,omitempty"`         // 是否邀请该成员使用企业微信（将通过微信服务通知或短信或邮件下发邀请，每天自动下发一次，最多持续3个工作日），默认值为true。
}

// User 成员结构
type UserDetail struct {
	UserID           string `json:"userid"`                      // 成员UserID
	Name             string `json:"name,omitempty"`              // 成员名称
	Alias            string `json:"alias,omitempty"`             // 成员别名
	Mobile           string `json:"mobile,omitempty"`            // 手机号码。企业内必须唯一，mobile/email二者不能同时为空
	Department       []int  `json:"department,omitempty"`        // 成员所属部门id列表,不超过100个
	Order            []int  `json:"order,omitempty"`             // 部门内的排序值，默认为0，成员次序以创建时间从小到大排列。个数必须和参数department的个数一致，数值越大排序越前面。有效的值范围是[0, 2^32)
	Position         string `json:"position,omitempty"`          // 职务信息。长度为0~128个字符
	Gender           string    `json:"gender,omitempty"`            // 性别。0表示未定义，1表示男性，2表示女性
	Email            string `json:"email,omitempty"`             // 邮箱。长度6~64个字节，且为有效的email格式。企业内必须唯一，mobile/email二者不能同时为空
	Telephone        string `json:"telephone,omitempty"`         // 座机。32字节以内，由纯数字或’-‘号组成。
	IsLeaderInDept   []int  `json:"is_leader_in_dept,omitempty"` // 个数必须和参数department的个数一致，表示在所在的部门内是否为上级。1表示为上级，0表示非上级。在审批等应用里可以用来标识上级审批人
	Avatar           string `json:"avatar,omitempty"`            // 头像url。 第三方仅通讯录应用可获取；对于非第三方创建的成员，第三方通讯录应用也不可获取
	ThumbAvatar      string `json:"thumb_avatar,omitempty"`      // 头像缩略图url。第三方仅通讯录应用可获取；对于非第三方创建的成员，第三方通讯录应用也不可获取
	Enable           int    `json:"enable,omitempty"`            // 启用/禁用成员。1表示启用成员，0表示禁用成员
	ExternalPosition string `json:"external_position,omitempty"` // 对外职务，如果设置了该值，则以此作为对外展示的职务，否则以position来展示。长度12个汉字内
	Address          string `json:"address,omitempty"`           // 地址。长度最大128个字符
	MainDepartment   int    `json:"main_department,omitempty"`   // 主部门
	Status           int    `json:"status"`                      // 激活状态: 1=已激活，2=已禁用，4=未激活，5=退出企业。
	QrCode           string `json:"qr_code,omitempty"`           // 员工个人二维码，扫描可添加为外部联系人
	OpenUserID       string `json:"open_userid,omitempty"`       // 全局唯一。对于同一个服务商，不同应用获取到企业内同一个成员的open_userid是相同的，最多64个字节。仅第三方应用可获取

}

// GetUserResp 获取成员响应
type GetUserResp struct {
	commons.CommonError
	UserDetail
}

// BatchDeleteUserReq 批量删除成员请求
type BatchDeleteUserReq struct {
	UserIDList []string `json:"useridlist"`
}

// DepartmentUser 部门成员细项
type DepartmentUser struct {
	UserID     string `json:"userid"`
	Name       string `json:"name"`
	Department []int  `json:"department"`
	OpenUserID string `json:"open_userid"`
}

// GetDepartmentUserResp 获取部门成员响应
type GetDepartmentUserResp struct {
	commons.CommonError
	UserList []DepartmentUser `json:"userlist"`
}

// GetDepartmentUserDetailResp 获取部门成员详情响应
type GetDepartmentUserDetailResp struct {
	commons.CommonError
	UserList []UserDetail `json:"userlist"`
}

// InviteUserReq 邀请成员请求
type InviteUserReq struct {
	User  []string `json:"user"`  // 成员ID列表, 最多支持1000个。
	Party []int    `json:"party"` // 部门ID列表，最多支持100个。
	Tag   []int    `json:"tag"`   // 标签ID列表，最多支持100个。
}

// InviteUserResp 邀请成员响应
type InviteUserResp struct {
	commons.CommonError
	InvaildUser  []string `json:"invaliduser"`  // 非法成员列表
	InvaildParty []int    `json:"invalidparty"` // 非法部门列表
	InvaildTag   []int    `json:"invalidtag"`   // 非法标签列表
}

// GetJoinQrcodeResp 获取加入企业二维码响应
type GetJoinQrcodeResp struct {
	commons.CommonError
	JoinQrcode string `json:"join_qrcode"` // 二维码链接，有效期7天
}

// GetActiveStatResp 获取企业活跃成员数响应
type GetActiveStatResp struct {
	commons.CommonError
	ActiveCount int `json:"active_cnt"` // 活跃成员数
}

// ================= 方法==========================

// CreateUser 创建成员
// 参考https://open.work.weixin.qq.com/api/doc/90000/90135/90195
func (manager *ContactManager) CreateUser(user CreateUserReq) (*commons.CommonError, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	url := fmt.Sprintf("%s?access_token=%s", CreateDepartmentURL, token)

	// 检查必填项
	if user.Name == "" || user.UserID == "" || len(user.Department) == 0 || user.Mobile == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}
	// 构造Body
	var body []byte
	body, err = commons.PostJSON(url, user)
	if err != nil {
		return nil, err
	}
	var resp commons.CommonError
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("CreateUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// UpdateUser 更新成员
// 参考https://open.work.weixin.qq.com/api/doc/90000/90135/90197
func (manager *ContactManager) UpdateUser(user UpdateUserReq) (*commons.CommonError, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	url := fmt.Sprintf("%s?access_token=%s", CreateDepartmentURL, token)

	// 检查必填项
	if user.UserID == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}
	// 构造Body
	var body []byte
	body, err = commons.PostJSON(url, user)
	if err != nil {
		return nil, err
	}
	var resp commons.CommonError
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("UpdateUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// DeleteUser 删除成员
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/90198
func (manager *ContactManager) DeleteUser(userID string) (*commons.CommonError, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	// 检查必填项
	if userID == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}

	url := fmt.Sprintf("%s?access_token=%s&userid=%s", DeleteUserURL, token, userID)

	// 构造Body
	var body []byte
	body, err = commons.HTTPGet(url)
	if err != nil {
		return nil, err
	}
	var resp commons.CommonError
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("DeleteUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// GetUser 获取成员
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/90196
func (manager *ContactManager) GetUser(userID string) (*GetUserResp, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	// 检查必填项
	if userID == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}

	url := fmt.Sprintf("%s?access_token=%s&userid=%s", GetUserURL, token, userID)

	// 构造Body
	var body []byte
	body, err = commons.HTTPGet(url)
	if err != nil {
		return nil, err
	}
	var resp GetUserResp
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("GetUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// BatchDeleteUser 删除成员
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/90199
func (manager *ContactManager) BatchDeleteUser(req BatchDeleteUserReq) (*commons.CommonError, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	url := fmt.Sprintf("%s?access_token=%s", DeleteUserURL, token)

	// 构造Body
	var body []byte
	body, err = commons.PostJSON(url, req)
	if err != nil {
		return nil, err
	}
	var resp commons.CommonError
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("BatchDeleteUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// GetDepartmentUser 获取部门成员，department_id，获取的部门id，必填。fetch_child，是否递归获取子部门下面的成员：1-递归获取，0-只获取本部门
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/90200
func (manager *ContactManager) GetDepartmentUser(departmentID string, fetchChild int) (*GetDepartmentUserResp, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	// 检查必填项
	if departmentID == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}

	url := fmt.Sprintf("%s?access_token=%s&department_id=%s&fetch_child=%d", GetDepartmentUserURL, token, departmentID, fetchChild)

	// 构造Body
	var body []byte
	body, err = commons.HTTPGet(url)
	if err != nil {
		return nil, err
	}
	var resp GetDepartmentUserResp
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("GetDepartmentUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// GetDepartmentUserDetail 获取部门成员详情，department_id，获取的部门id，必填。fetch_child，是否递归获取子部门下面的成员：1-递归获取，0-只获取本部门
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/90200
func (manager *ContactManager) GetDepartmentUserDetail(departmentID string, fetchChild int) (*GetDepartmentUserDetailResp, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	// 检查必填项
	if departmentID == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}

	url := fmt.Sprintf("%s?access_token=%s&department_id=%s&fetch_child=%d", GetDepartmentUserDetailURL, token, departmentID, fetchChild)

	// 构造Body
	var body []byte
	body, err = commons.HTTPGet(url)
	if err != nil {
		return nil, err
	}
	var resp GetDepartmentUserDetailResp
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("GetDepartmentUserDetail error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// InviteUser 邀请成员
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/90975
func (manager *ContactManager) InviteUser(req InviteUserReq) (*InviteUserResp, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	url := fmt.Sprintf("%s?access_token=%s", InviteUserURL, token)

	if len(req.User) == 0 && len(req.Party) == 0 && len(req.Tag) == 0 {
		return nil, errors.New(commons.ErrParamInValid)
	}
	// 构造Body
	var body []byte
	body, err = commons.PostJSON(url, req)
	if err != nil {
		return nil, err
	}
	var resp InviteUserResp
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("InviteUser error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// GetJoinQrcode 获取加入企业二维码，
// 二维码类型size_type,qrcode尺寸类型，1: 171 x 171; 2: 399 x 399; 3: 741 x 741; 4: 2052 x 2052
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/91714
func (manager *ContactManager) GetJoinQrcode(sizeType int) (*GetJoinQrcodeResp, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	// 检查必填项
	if sizeType < 1 || sizeType > 4 {
		return nil, errors.New(commons.ErrParamInValid)
	}

	url := fmt.Sprintf("%s?access_token=%s&size_type=%d", GetJoinQrcodeURL, token, sizeType)

	// 构造Body
	var body []byte
	body, err = commons.HTTPGet(url)
	if err != nil {
		return nil, err
	}
	var resp GetJoinQrcodeResp
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("GetJoinQrcode error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}

// GetActiveStat 获取企业活跃成员数,date具体某天的活跃人数，最长支持获取30天前数据
// 参考 https://open.work.weixin.qq.com/api/doc/90000/90135/92714
func (manager *ContactManager) GetActiveStat(date string) (*GetActiveStatResp, error) {
	token, err := manager.getToken()
	if err != nil {
		return nil, err
	}
	// 检查必填项
	if date == "" {
		return nil, errors.New(commons.ErrParamInValid)
	}

	url := fmt.Sprintf("%s?access_token=%s", GetActiveStatURL, token)

	// 创建匿名结构体
	dateStruct := struct {
		Date string `json:"date"`
	}{
		Date: date,
	}

	// 构造Body
	var body []byte
	body, err = commons.PostJSON(url, dateStruct)
	if err != nil {
		return nil, err
	}
	var resp GetActiveStatResp
	err = json.Unmarshal(body, &resp)
	if err != nil {
		return nil, err
	}
	// 出错返回码，为0表示成功，非0表示调用失败
	if resp.ErrCode != 0 {
		err = fmt.Errorf("GetActiveStat error : errcode=%v , errormsg=%v", resp.ErrCode, resp.ErrMsg)
		return nil, err
	}
	return &resp, nil
}
